﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.OleDb;
using System.IO.Ports;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using IronPython.Hosting;
using Microsoft.Office.Interop.Excel;
using Microsoft.Scripting.Hosting;
using PowerMonitor.BaseCtrl;
using PowerMonitor.Common;
using PowerMonitor.ModbusDev;
using PowerMonitor.Properties;
using Application = System.Windows.Forms.Application;
using MenuItem = System.Windows.Forms.MenuItem;

namespace PowerMonitor
{
    class AppMain
    {
        
        public static PowerMonitor MainForm;
        //public static User gUser;
        public static List<Channel> ChlList = new List<Channel>();
        public static string StartPath = Application.StartupPath; // 程序运行目录
        public static string strErrMsgFileName = "ErrMsg.txt"; // 错误报文信息
        public static string strErrMsgStaFileName = "ErrSta.txt"; // 错误报文统计信息
        public static INIFile iniConfig = new INIFile(StartPath);
        public static Queue<msgInfo> msgQueue = new Queue<msgInfo>();

        public static System.Drawing.Color[] AvailableColors = new System.Drawing.Color[] {
            System.Drawing.Color.LightBlue,System.Drawing.Color.Red, System.Drawing.Color.Blue, System.Drawing.Color.Green, System.Drawing.Color.LimeGreen, System.Drawing.Color.Yellow, System.Drawing.Color.Orange, System.Drawing.Color.Navy, System.Drawing.Color.AliceBlue, System.Drawing.Color.AntiqueWhite, System.Drawing.Color.Aqua, System.Drawing.Color.Aquamarine, System.Drawing.Color.Azure, System.Drawing.Color.Beige, System.Drawing.Color.Bisque, System.Drawing.Color.BlanchedAlmond,
            System.Drawing.Color.BlueViolet, System.Drawing.Color.Brown, System.Drawing.Color.BurlyWood, System.Drawing.Color.CadetBlue, System.Drawing.Color.Chartreuse, System.Drawing.Color.Chocolate, System.Drawing.Color.Coral, System.Drawing.Color.CornflowerBlue, System.Drawing.Color.Cornsilk, System.Drawing.Color.Crimson, System.Drawing.Color.Cyan, System.Drawing.Color.DarkBlue, System.Drawing.Color.DarkCyan, System.Drawing.Color.DarkGoldenrod, System.Drawing.Color.DarkGray,
            System.Drawing.Color.DarkGreen, System.Drawing.Color.DarkKhaki, System.Drawing.Color.DarkMagenta, System.Drawing.Color.DarkOliveGreen, System.Drawing.Color.DarkOrange, System.Drawing.Color.DarkOrchid, System.Drawing.Color.DarkRed, System.Drawing.Color.DarkSalmon, System.Drawing.Color.DarkSeaGreen, System.Drawing.Color.DarkSlateBlue, System.Drawing.Color.DarkSlateGray, System.Drawing.Color.DarkTurquoise, System.Drawing.Color.DarkViolet, System.Drawing.Color.DeepPink, System.Drawing.Color.DeepSkyBlue, System.Drawing.Color.DimGray,
            System.Drawing.Color.DodgerBlue, System.Drawing.Color.Firebrick, System.Drawing.Color.FloralWhite, System.Drawing.Color.ForestGreen, System.Drawing.Color.Fuchsia, System.Drawing.Color.Gainsboro, System.Drawing.Color.GhostWhite, System.Drawing.Color.Gold, System.Drawing.Color.Goldenrod, System.Drawing.Color.GreenYellow, System.Drawing.Color.Honeydew, System.Drawing.Color.HotPink, System.Drawing.Color.IndianRed, System.Drawing.Color.Indigo, System.Drawing.Color.Ivory, System.Drawing.Color.Khaki,
            System.Drawing.Color.Lavender, System.Drawing.Color.LavenderBlush, System.Drawing.Color.LawnGreen, System.Drawing.Color.LemonChiffon,  System.Drawing.Color.LightCoral, System.Drawing.Color.LightCyan, System.Drawing.Color.LightGoldenrodYellow, System.Drawing.Color.LightGray, System.Drawing.Color.LightGreen, System.Drawing.Color.LightPink, System.Drawing.Color.LightSalmon, System.Drawing.Color.LightSeaGreen, System.Drawing.Color.LightSkyBlue, System.Drawing.Color.LightSlateGray, System.Drawing.Color.LightSteelBlue,
            System.Drawing.Color.LightYellow, System.Drawing.Color.Lime, System.Drawing.Color.Linen, System.Drawing.Color.Magenta, System.Drawing.Color.Maroon, System.Drawing.Color.MediumAquamarine, System.Drawing.Color.MediumBlue, System.Drawing.Color.MediumOrchid, System.Drawing.Color.MediumPurple, System.Drawing.Color.MediumSeaGreen, System.Drawing.Color.MediumSlateBlue, System.Drawing.Color.MediumSpringGreen, System.Drawing.Color.MediumTurquoise, System.Drawing.Color.MediumVioletRed, System.Drawing.Color.MidnightBlue, System.Drawing.Color.MintCream,
            System.Drawing.Color.MistyRose, System.Drawing.Color.Moccasin, System.Drawing.Color.NavajoWhite, System.Drawing.Color.OldLace, System.Drawing.Color.Olive, System.Drawing.Color.OliveDrab, System.Drawing.Color.OrangeRed, System.Drawing.Color.Orchid, System.Drawing.Color.PaleGoldenrod, System.Drawing.Color.PaleGreen, System.Drawing.Color.PaleTurquoise, System.Drawing.Color.PaleVioletRed, System.Drawing.Color.PapayaWhip, System.Drawing.Color.PeachPuff, System.Drawing.Color.Peru, System.Drawing.Color.Pink,
            System.Drawing.Color.Plum, System.Drawing.Color.PowderBlue, System.Drawing.Color.Purple, System.Drawing.Color.RosyBrown, System.Drawing.Color.RoyalBlue, System.Drawing.Color.SaddleBrown, System.Drawing.Color.Salmon, System.Drawing.Color.SandyBrown, System.Drawing.Color.SeaGreen, System.Drawing.Color.SeaShell, System.Drawing.Color.Sienna, System.Drawing.Color.Silver, System.Drawing.Color.SkyBlue, System.Drawing.Color.SlateBlue, System.Drawing.Color.SlateGray, System.Drawing.Color.Snow,
            System.Drawing.Color.SpringGreen, System.Drawing.Color.SteelBlue, System.Drawing.Color.Tan, System.Drawing.Color.Teal, System.Drawing.Color.Thistle, System.Drawing.Color.Tomato, System.Drawing.Color.Transparent, System.Drawing.Color.Turquoise, System.Drawing.Color.Violet, System.Drawing.Color.Wheat, System.Drawing.Color.White, System.Drawing.Color.WhiteSmoke, System.Drawing.Color.YellowGreen, System.Drawing.Color.Black};

        //public static string strRegID = "";

        public static bool isRegisted = true;
        // 以下为IronPython 操作对象
        private static ScriptEngine _ScptEngine; //= IronPython.Hosting.Python.CreateEngine(); // 创建时间大约2~3秒
        public static ScriptEngine ScptEngine
        {
            get 
            { 
                if (_ScptEngine == null)
                {
                    _ScptEngine = Python.CreateEngine();
                    
                }
                return _ScptEngine; 
            }
            //set { AppMain._ScptEngine = value; }
        }
        public static StringBuilder IronPythonHeader = new StringBuilder( "import clr\r\nclr.AddReferenceByPartialName(\"System.Windows.Forms\")\r\n"+
                                                   "clr.AddReferenceByPartialName(\"System.Drawing\")\r\nfrom System.Windows.Forms import *\r\nfrom System.Drawing import *\r\n");
        

        private AppMain()
        {
        }
        /// <summary>
        /// 启用所有通道
        /// </summary>
        public static void StartAllChl()
        {
            for (int i = 0; i < ChlList.Count; i++)
            {
                ChlList[i].StartPolling();
            }
            msgQueue.Clear();
        }
        /// <summary>
        /// 停用所有通道
        /// </summary>
        public static void StopAllChl()
        {
            for (int i = 0; i < ChlList.Count; i++)
            {
                ChlList[i].StopPolling();
            }
            msgQueue.Clear();
        }
        /// <summary>
        /// 保存通道参数至数据库（保存所有参数）
        /// </summary>
        /// <returns></returns>
        public static bool SaveChlParaToDB()
        {
            historytable = "";
            string strInsertSQL = "Insert INTO Channel_Lib(通道号,通道名称,是否启用,通道类型,轮询周期,使用端口,波特率,超时时间,奇偶校验,数据位,停止位) Values" +
                            "(@ChlId,@ChlName,@IsWorking,@ChlType,@ChlT,@ChlCom,@Baudrate,@TimeOut,@Parity,@DataBits,@StopBits)";
            using(OleDbConnection con = new OleDbConnection(dbOper.M_str_sqlcon))
            {
                con.Open();
                OleDbCommand cmd = new OleDbCommand(strInsertSQL, con);
                cmd.CommandText = "delete * from Channel_Lib";// where 通道号=" + InnerChl.ComChlPara.ChannelId.ToString();
                cmd.ExecuteNonQuery(); // 级联删除通道 然后重新插入
                for (int i = 0; i < ChlList.Count;i++ )
                {
                    if (ChlList[i] is InnerModbusChannel)
                    {
                        cmd.Parameters.Clear();
                        InnerModbusChannel InnerChl = ChlList[i] as InnerModbusChannel;
                        cmd.Parameters.Add("@ChlId", OleDbType.Integer).Value = InnerChl.ComChlPara.ChannelId;
                        cmd.Parameters.Add("@ChlName", OleDbType.VarChar, 50).Value = InnerChl.ComChlPara.ChannelName;
                        cmd.Parameters.Add("@IsWorking", OleDbType.Boolean).Value = InnerChl.ComChlPara.isWorking;
                        cmd.Parameters.Add("@ChlType", OleDbType.VarChar, 30).Value = InnerChl.ToString();
                        cmd.Parameters.Add("@ChlT", OleDbType.Integer).Value = InnerChl.PollingTime;
                        cmd.Parameters.Add("@ChlCom", OleDbType.VarChar, 10).Value = InnerChl.ComChlPara.ComPort.PortName;
                        cmd.Parameters.Add("@Baudrate", OleDbType.Integer).Value = InnerChl.ComChlPara.ComPort.BaudRate;
                        cmd.Parameters.Add("@TimeOut", OleDbType.Integer).Value = InnerChl.ComChlPara.iTimeOut;
                        cmd.Parameters.Add("@Parity", OleDbType.VarChar, 15).Value = InnerChl.ComChlPara.ComPort.Parity.ToString();
                        cmd.Parameters.Add("@DataBits", OleDbType.VarChar, 15).Value = InnerChl.ComChlPara.ComPort.DataBits.ToString();
                        cmd.Parameters.Add("@StopBits", OleDbType.VarChar, 15).Value = InnerChl.ComChlPara.ComPort.StopBits.ToString();
                        try
                        {
                            cmd.CommandText = strInsertSQL;
                            cmd.ExecuteNonQuery();
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                            return false;
                        }
                        SaveDevParaToDB(InnerChl,con);
                    }
                }
            }
            return true;
        }
        /// <summary>
        /// 更新通道参数至数据库
        /// </summary>
        /// <returns></returns>
        public static bool UpdateChlParaToDB(Channel chl)
        {
            string strUpdateSql = "update Channel_Lib set 通道名称=@ChlName,是否启用=@IsWorking,通道类型=@ChlType,轮询周期=@ChlT,使用端口=@ChlCom,波特率=@Baudrate,超时时间=@TimeOut,奇偶校验=@Parity,数据位=@DataBits,停止位=@StopBits " +
                            " where 通道号 = @ChlId";
            using (OleDbConnection con = new OleDbConnection(dbOper.M_str_sqlcon))
            {
                try
                {
                    con.Open();
                    OleDbCommand cmd = new OleDbCommand(strUpdateSql, con);
                    if (chl is InnerModbusChannel)
                    {
                        cmd.Parameters.Clear();
                        InnerModbusChannel InnerChl = chl as InnerModbusChannel;
                       
                        cmd.Parameters.Add("@ChlName", OleDbType.VarChar, 50).Value = InnerChl.ComChlPara.ChannelName;
                        cmd.Parameters.Add("@IsWorking", OleDbType.Boolean).Value = InnerChl.ComChlPara.isWorking;
                        cmd.Parameters.Add("@ChlType", OleDbType.VarChar, 30).Value = InnerChl.ToString();
                        cmd.Parameters.Add("@ChlT", OleDbType.Integer).Value = InnerChl.PollingTime;
                        cmd.Parameters.Add("@ChlCom", OleDbType.VarChar, 10).Value =
                            InnerChl.ComChlPara.ComPort.PortName;
                        cmd.Parameters.Add("@Baudrate", OleDbType.Integer).Value = InnerChl.ComChlPara.ComPort.BaudRate;
                        cmd.Parameters.Add("@TimeOut", OleDbType.Integer).Value = InnerChl.ComChlPara.iTimeOut;
                        cmd.Parameters.Add("@Parity", OleDbType.VarChar, 15).Value =
                            InnerChl.ComChlPara.ComPort.Parity.ToString();
                        cmd.Parameters.Add("@DataBits", OleDbType.VarChar, 15).Value =
                            InnerChl.ComChlPara.ComPort.DataBits.ToString();
                        cmd.Parameters.Add("@StopBits", OleDbType.VarChar, 15).Value =
                            InnerChl.ComChlPara.ComPort.StopBits.ToString();
                        cmd.Parameters.Add("@ChlId", OleDbType.Integer).Value = InnerChl.ComChlPara.ChannelId;
                        cmd.CommandText = strUpdateSql;
                        cmd.ExecuteNonQuery();
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    return false;
                }
            }
            return true;
        }
        /// <summary>
        /// 保存装置参数至数据库
        /// </summary>
        /// <returns></returns>
        public static bool SaveDevParaToDB(Channel Chl, OleDbConnection con)
        {
            string strInsertSQL = "Insert INTO Device_Lib(通道号,设备号,装置名称,装置地址,字节顺序,重发次数,断线触发,启用否,设备层脚本) Values" +
                                    "(@ChlId,@DevId,@DevName,@DevAddr,@ByteSqueue,@ReSend,@BreakCnt,@IsWorking,@Script)";
           
            //con.Open();
            OleDbCommand cmd = new OleDbCommand(strInsertSQL, con);
                
            if (Chl is InnerModbusChannel)
            {
                InnerModbusChannel InnerChl = Chl as InnerModbusChannel;
                Application.DoEvents();
                cmd.CommandText = strInsertSQL;
                for (int i = 0; i < InnerChl.m_DeviceList.Count; i++)
                {
                    cmd.Parameters.Clear();
                    cmd.Parameters.Add("@ChlId", OleDbType.Integer).Value = InnerChl.ComChlPara.ChannelId; // 通道号从通道获取  
                    cmd.Parameters.Add("@DevId", OleDbType.Integer).Value = InnerChl.m_DeviceList[i].DeviceId;
                    cmd.Parameters.Add("@DevName", OleDbType.VarChar, 50).Value = InnerChl.m_DeviceList[i].Name;
                    cmd.Parameters.Add("@DevAddr", OleDbType.Integer).Value = InnerChl.m_DeviceList[i].bAddr;
                    cmd.Parameters.Add("@ByteSqueue", OleDbType.VarChar, 10).Value = InnerChl.m_DeviceList[i].byteSqueue.ToString();
                    cmd.Parameters.Add("@ReSend", OleDbType.Integer).Value = InnerChl.m_DeviceList[i].MaxSendCnt;
                    cmd.Parameters.Add("@BreakCnt", OleDbType.Integer).Value = InnerChl.m_DeviceList[i].BreakOffCnt;
                    cmd.Parameters.Add("@IsWorking", OleDbType.Boolean).Value = InnerChl.m_DeviceList[i].isWorking;
                    cmd.Parameters.AddWithValue("@Script", InnerChl.m_DeviceList[i].Expression);
                    try
                    {
                        cmd.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        return false;
                    }
                    SaveInnerModbusDataTemplate(InnerChl.ComChlPara.ChannelId, InnerChl.m_DeviceList[i], con);
                    Application.DoEvents();
                }
            }
            return true;
        }
        /// <summary>
        /// 更改装置参数至数据库
        /// </summary>
        /// <returns></returns>
        public static bool UpdateDevParaToDB(Int32 chlId, BaseDevice dev, OleDbConnection con)
        {
            const string strUpdateSql = "update Device_Lib set 装置名称= @DevName,装置地址=@DevAddr,字节顺序=@ByteSqueue,重发次数=@ReSend,断线触发=@BreakCnt,启用否=@IsWorking,设备层脚本=@Script " +
                                        "where 通道号=@ChlId and 设备号=@DevId";

            con.Open();
            OleDbCommand cmd = new OleDbCommand(strUpdateSql, con);

            if (dev is InnerModbusDevice)
            {
                cmd.CommandText = strUpdateSql;
                cmd.Parameters.Clear();
                   
                cmd.Parameters.Add("@DevName", OleDbType.VarChar, 50).Value = dev.Name;
                cmd.Parameters.Add("@DevAddr", OleDbType.Integer).Value = dev.bAddr;
                cmd.Parameters.Add("@ByteSqueue", OleDbType.VarChar, 10).Value = dev.byteSqueue.ToString();
                cmd.Parameters.Add("@ReSend", OleDbType.Integer).Value = dev.MaxSendCnt;
                cmd.Parameters.Add("@BreakCnt", OleDbType.Integer).Value = dev.BreakOffCnt;
                cmd.Parameters.Add("@IsWorking", OleDbType.Boolean).Value = dev.isWorking;
                cmd.Parameters.AddWithValue("@Script", dev.Expression);
                cmd.Parameters.Add("@ChlId", OleDbType.Integer).Value = chlId; // 通道号从通道获取  
                cmd.Parameters.Add("@DevId", OleDbType.Integer).Value = dev.DeviceId;
                try
                {
                    cmd.ExecuteNonQuery();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    return false;
                }
                return true;
            }
            return false;
        }

        public static bool SaveInnerModbusDataTemplate(int iChlId,InnerModbusDevice dev,OleDbConnection con)
        {
            if (dev == null|| dev.GetDataItemCnt() ==0)
            {
                return false;
            }
            string strDataItem = "Insert INTO ModDevData_Lib(通道号,设备号,数据点号,数据名称,功能码,数据地址,值类型,缩放倍率,锁定否,是否存储,存储周期,数据层脚本,是否读取) Values" +
                        "(@ChlId,@DevId,@DataId,@DataName,@FunConde,@RegAddr,@DataType,@Multiple,@IsLock,@IsSave,@SaveCycle,@Script,@isRead)";
            OleDbCommand cmd = new OleDbCommand(strDataItem, con);
            for (int i = 0; i < dev.GetDataItemCnt(); i++)
            {
                cmd.Parameters.Clear();
                cmd.Parameters.Add("@ChlId", OleDbType.Integer).Value = iChlId;         
                cmd.Parameters.Add("@DevId", OleDbType.Integer).Value = dev.DeviceId;
                cmd.Parameters.Add("@DataId", OleDbType.Integer).Value = i;
                cmd.Parameters.Add("@DataName", OleDbType.VarChar, 50).Value = dev.GetDataItem(i).Name;
                cmd.Parameters.Add("@FunConde", OleDbType.Integer).Value = dev.GetDataItem(i).bFunCode;
                cmd.Parameters.Add("@RegAddr", OleDbType.Integer).Value = dev.GetDataItem(i).usRegAddr;
                cmd.Parameters.Add("@DataType", OleDbType.VarChar, 10).Value = dev.GetDataItem(i).dataType.ToString();
                cmd.Parameters.Add("@Multiple", OleDbType.Single).Value = dev.GetDataItem(i).dmult;
                cmd.Parameters.Add("@IsLock", OleDbType.Boolean).Value = dev.GetDataItem(i).isLock;
                cmd.Parameters.Add("@IsSave", OleDbType.Boolean).Value = dev.GetDataItem(i).IsSave;
                cmd.Parameters.Add("@SaveCycle", OleDbType.Integer).Value = dev.GetDataItem(i).SaveCycle;
                cmd.Parameters.AddWithValue("@Script",dev.GetDataItem(i).Expression);
                cmd.Parameters.Add("@isRead", OleDbType.Boolean).Value = dev.GetDataItem(i).IsSummation;
                try
                {
                    cmd.ExecuteNonQuery();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    return false;
                }
            }
            return true;
        }
        /// <summary>
        /// 从数据库装载通道参数
        /// </summary>
        /// <returns></returns>
        public static bool LoadChlParaFromDB()
        {
            using (OleDbConnection con = new OleDbConnection(dbOper.M_str_sqlcon))
            {
                try
                {
                    ChlList.Clear(); // 清空
                    con.Open();
                    OleDbCommand Cmd = new OleDbCommand("Select 通道类型,通道号,通道名称,是否启用,轮询周期,超时时间,使用端口,波特率,奇偶校验,数据位,停止位 from Channel_Lib order by 通道号", con); // 此处传入string strSQL则会出现无法查询的现象？？？
                    OleDbDataReader dbReader = Cmd.ExecuteReader(); // DbCtrl.GetCmd(strSQL);
                    while (dbReader.Read())
                    {
                        switch (dbReader.GetString(0) as string)
                        {
                            case "ModbusRTU_InnerChannel":
                                InnerModbusChannel channel = new InnerModbusChannel();
                                channel.ComChlPara.ChannelId = dbReader.GetInt32(1);
                                channel.ComChlPara.ChannelName = dbReader.GetString(2);
                                channel.ComChlPara.isWorking = dbReader.GetBoolean(3);
                                channel.PollingTime = dbReader.GetInt32(4);
                                channel.ComChlPara.iTimeOut = dbReader.GetInt32(5); // 已经内部设置串口超时
                                channel.ComChlPara.ComPort.PortName =dbReader.GetString(6);
                                channel.ComChlPara.ComPort.BaudRate = dbReader.GetInt32(7);
                                channel.ComChlPara.ComPort.Parity = (Parity)Enum.Parse(typeof(Parity), dbReader.GetString(8));
                                channel.ComChlPara.ComPort.DataBits = Int32.Parse(dbReader.GetString(9));
                                channel.ComChlPara.ComPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), dbReader.GetString(10));
                                ChlList.Add(channel);
                                break;
                        }
                    }
                    RefreshChlId();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    return false;
                }
            }
            return true;
        }
        /// <summary>
        /// 从数据库装载装置参数
        /// </summary>
        /// <param name="Chl"></param>
        /// <returns></returns>
        public static bool LoadDevParaFromDB(ref Channel Chl)
        {
            using (OleDbConnection con = new OleDbConnection(dbOper.M_str_sqlcon))
            {
                string strSQL = "";
                strSQL = string.Format("select 设备号,装置名称,装置地址,重发次数,断线触发,启用否,字节顺序,设备层脚本 from Device_Lib where 通道号 = {0} order by 设备号", Chl.baseChlPara.ChannelId);
                try
                {
                    con.Open();
                    OleDbCommand Cmd = new OleDbCommand(strSQL, con); // 此处传入string strSQL则会出现无法查询的现象？？？
                    OleDbDataReader dbReader = Cmd.ExecuteReader(); // DbCtrl.GetCmd(strSQL);
                    while (dbReader.Read())
                    {
                        switch (Chl.ToString())
                        {
                            case "ModbusRTU_InnerChannel":
                                InnerModbusDevice Device = new InnerModbusDevice();
                                Device.ChannelId = Chl.baseChlPara.ChannelId;
                                Device.DeviceId = dbReader.GetInt32(0);
                                Device.Name = dbReader.GetString(1);
                                Device.bAddr = dbReader.GetByte(2);
                                Device.MaxSendCnt = dbReader.GetInt32(3);
                                Device.BreakOffCnt = dbReader.GetInt32(4);
                                Device.isWorking = dbReader.GetBoolean(5);
                                Device.byteSqueue = (eByteSqueue)Enum.Parse(typeof(eByteSqueue), dbReader.GetString(6));
                                if (!dbReader.IsDBNull(7))
                                {
                                    Device.Expression = dbReader.GetString(7);
                                }
                                (Chl as InnerModbusChannel).m_DeviceList.Add(Device);
                                LoadInnerModDevDataItem(Chl.baseChlPara.ChannelId, ref Device, con); // 读取数据项
                                break;
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    return false;
                }
            }
            return true;
        }
        public static bool LoadInnerModDevDataItem(int iChl,ref InnerModbusDevice dev, OleDbConnection con)
        {
            string strSQL = "";

            strSQL = string.Format("select 数据名称,功能码,数据地址,值类型,缩放倍率,锁定否,是否存储,存储周期,数据层脚本,是否读取 from ModDevData_Lib where 通道号 = {0} and 设备号 = {1} order by 数据点号", iChl, dev.DeviceId);
            try
            {
                OleDbCommand Cmd = new OleDbCommand(strSQL, con); // 此处传入string strSQL则会出现无法查询的现象？？？
                OleDbDataReader dbReader = Cmd.ExecuteReader(); // DbCtrl.GetCmd(strSQL);
                dev.GetDataList().Clear();
                int count = 0;
                while (dbReader.Read())
                {
                    DevDataItem dataItem = new DevDataItem();
                    dataItem.ItemId = count;
                    count ++;
                    dataItem.Name = dbReader.GetString(0);
                    dataItem.bFunCode = dbReader.GetByte(1);
                    dataItem.usRegAddr = (ushort)dbReader.GetInt16(2);
                    dataItem.dataType = (eDataType)Enum.Parse(typeof(eDataType), dbReader.GetString(3));
                    dataItem.dmult = dbReader.GetFloat(4);
                    dataItem.isLock = dbReader.GetBoolean(5);
                    dataItem.IsSave = dbReader.GetBoolean(6);
                    dataItem.SaveCycle = dbReader.GetInt32(7);
                    if (!dbReader.IsDBNull(8))
                    {
                        dataItem.Expression = dbReader.GetString(8);
                    }
                    dataItem.IsSummation = dbReader.GetBoolean(9);
                    dev.GetDataList().Add(dataItem);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return false;
            }
            return true;
        }
        /// <summary>
        /// 从数据库装载通道及装置参数
        /// </summary>
        /// <returns></returns>
        public static bool LoadChlDevPara()
        {
            bool res = true;
            if (LoadChlParaFromDB())
            {
                Channel chl = null;
                for (int i = 0; i < ChlList.Count;i++)
                {
                    chl = ChlList[i];
                    if (!LoadDevParaFromDB(ref chl))
                    {
                        ChlList.Clear();
                        res = false;
                        break;
                    }
                }
            } 
            else
            {
                ChlList.Clear();
                res = false;
            }
            return res;
        }

        protected static  BackgroundWorker SaveHistoryThread = new BackgroundWorker();     // 数据存储线程
        private static string historytable = "";
        /// <summary>
        /// 数据存储存储线程
        /// </summary>
        /// <returns></returns>
        public static bool BeginSaveToHistory()
        {
            if (SaveHistoryThread.IsBusy)
            {
                return false;
            }
            if (!historytable.Contains(DateTime.Now.ToString("yyyyMM")))
            {
                historytable = Resources.HistoryTableName + DateTime.Now.ToString("yyyyMM");
                using (OleDbConnection con = new OleDbConnection(dbOper.M_str_sqlcon))
                {
                    try
                    {
                        OleDbCommand cmd = new OleDbCommand();
                        cmd.Connection = con;
                        cmd.CommandText = string.Format("select * into {0} from HistoryData", historytable);//"create table {0} as select dataid,time,datavalue from HistoryData definition only"
                        con.Open();
                        cmd.ExecuteNonQuery();

                    }
                    catch(Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
            }
            if (string.IsNullOrEmpty(historytable))
            {
                return false;
            }

            SaveHistoryThread.WorkerSupportsCancellation = true;
            SaveHistoryThread.DoWork += SaveDevItemDataToDb;
            SaveHistoryThread.RunWorkerCompleted += SaveHistoryThread_RunWorkerCompleted;
            SaveHistoryThread.RunWorkerAsync();
            return true;
        }

        private static void SaveHistoryThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
           if (SaveHistoryThread!=null)
           {
                SaveHistoryThread.DoWork -= SaveDevItemDataToDb;
                SaveHistoryThread.RunWorkerCompleted -= SaveHistoryThread_RunWorkerCompleted;
            }
        }

        static int SaveHour = -1; // 记录整点存储
        public static void SaveDevItemDataToDb(Object sender, DoWorkEventArgs e)
        {
            if (historytable == "" || ChlList.Count ==0)
            {
                return ;
            }
            using (OleDbConnection con = new OleDbConnection(dbOper.M_str_sqlcon))
            {
                try
                {
                    OleDbCommand cmd = new OleDbCommand();
                    cmd.Connection = con;
                    con.Open();
                    cmd.CommandText = string.Format("insert into {0}(dataid,savetime,datavalue)values(@dataid,@curtime,@curvalue)", historytable);
                    Int32 dataid = 0;
                    StringBuilder strCurTime = new StringBuilder();
                    float curdata = 0;
                    DateTime datetime = DateTime.Now; // 存储时间
                    if (datetime.Minute == 0 && SaveHour != datetime.Hour) // 整点存储
                    {
                        SaveHour = datetime.Hour;
                    }
                    else if (datetime.Minute == 0 && SaveHour == datetime.Hour)
                    {
                        return;
                    }
                    for (int i = 0; i < ChlList.Count;i++ )
                    {
                        if (ChlList[i].GetChannelState() == false)
                        {
                            continue;
                        }
                        for (int j = 0; j < ChlList[i].GetDevicesCnt();j++ )
                        {
                            BaseDevice dev= ChlList[i].GetDevByIndex(j);
                            if (!dev.isConnected)
                            {
                                continue;
                            } 
                            for (int k = 0; k < dev.GetDataItemCnt() ; k++)
                            {
                                DevDataItem item =dev.GetDataItem(k);
                                if (!item.IsSave || (datetime.Minute != 0 &&((datetime - item.SaveTime).TotalMinutes < item.SaveCycle))) // 
                                {
                                    continue;
                                }
                                dataid = (Int32)(i << 24) + (Int32)(j << 16) + k;
                                //strCurTime.Clear();
                                //strCurTime.Append(datetime.ToString("dd-HH:mm:ss")); // 以字符串存储方式查询效率低
                                curdata = (float)dev.GetDataItem(k).dCurValue;
                                cmd.Parameters.Clear();
                                cmd.Parameters.AddWithValue("@dataid", dataid);
                                cmd.Parameters.AddWithValue("@curtime", (Int32)(datetime.Day << 16) + (Int32)(datetime.Hour << 8) + datetime.Minute);
                                cmd.Parameters.AddWithValue("@curdata", curdata);
                                cmd.ExecuteNonQuery();
                                item.SaveTime = datetime; 
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    return ;
                }

            }
            return;
        }

        /// <summary>
        /// 以复制粘贴方式实现DataGridView内容导出到Excel中
        /// </summary>
        /// <param name="dgv">DataGridView源</param>
        /// <param name="strTitle">报表的标题</param>
        static public void DataGridViewCopyToExcel(DataGridView dgv, string strTitle)
        {

            if (dgv == null || dgv.Rows.Count == 0)
            {
                MessageBox.Show(Resources.msgNoDataInTable, Resources.msgTitleTip, MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
            }
            else
            {
                //选择创建文件的路径
                SaveFileDialog save = new SaveFileDialog();
                save.DefaultExt = "xls";
                save.AddExtension = true;
                save.Filter = Resources.txtSaveFileFilterXlsx; 
                save.Title = Properties.Resources.txtExportPath;
                //save.InitialDirectory = strDefPath;
                //save.FileName = strDefPath;
                if (save.ShowDialog() != DialogResult.OK)
                {
                    return;
                }
                string fileName = save.FileName;
                dgv.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;
                dgv.SelectAll(); // 选择全部单元格
                Clipboard.SetDataObject(dgv.GetClipboardContent(), false, 0, 10); // 复制所选择的单元格

                Microsoft.Office.Interop.Excel.Application excel = null;
                WaitingForm wating = new WaitingForm((sender, arg) =>
                {
                    try
                    {
                        // 创建Excel对象

                        excel = new Microsoft.Office.Interop.Excel.Application();
                        if (excel == null)
                        {
                            MessageBox.Show(Resources.MsgCannotOpenExcel, Resources.msgTitleTip, MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                            return;
                        }
                        //创建Excel工作薄
                        Microsoft.Office.Interop.Excel.Workbook excelBook = excel.Workbooks.Add(true);
                        Microsoft.Office.Interop.Excel.Worksheet excelSheet = null;
                        // 创建工作表
                        //excelBook.Worksheets.Add(Type.Missing, Type.Missing, Type.Missing, Type.Missing);

                        excelSheet = (Microsoft.Office.Interop.Excel.Worksheet)excelBook.Worksheets[1];
                        excelSheet.PasteSpecial(); // 粘贴
                        excelSheet.Rows[1].Insert();
                        excel.Cells[1, 1] = strTitle;
                        excel.Cells[1, 2] = Resources.txtQueryTime;
                        excel.Cells[1, 3] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        //excel.Cells[2, 1] = DateTime.Now.ToLongDateString();
                        Microsoft.Office.Interop.Excel.Range myrange = excelSheet.Range["A2"];
                        myrange.EntireColumn.AutoFit();//列宽自适应


                        int FormatNum;//保存excel文件的格式
                        string Version;//excel版本号
                        Version = excel.Version;//获取你使用的excel 的版本号
                        if (Convert.ToDouble(Version) < 12)//You use Excel 97-2003
                        {
                            FormatNum = -4143;
                            excelBook.SaveAs(fileName, FormatNum, Missing.Value, Missing.Value, Missing.Value,
                                        Missing.Value, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlShared, Missing.Value, Missing.Value, Missing.Value,
                                        Missing.Value, Missing.Value);
                        }
                        else//you use excel 2007 or later
                        {
                            if (fileName.Contains(".xlsx"))
                            {
                                excelBook.SaveAs(fileName, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
                                           Missing.Value, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlShared, Missing.Value, Missing.Value, Missing.Value,
                                           Missing.Value, Missing.Value);
                            }
                            else
                            {
                                FormatNum = 56;
                                excelBook.SaveAs(fileName, FormatNum, Missing.Value, Missing.Value, Missing.Value,
                                            Missing.Value, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlShared, Missing.Value, Missing.Value, Missing.Value,
                                            Missing.Value, Missing.Value);
                            }
                        }
                        excel.Quit();  // 保存后应该关闭EXCEL
                        MessageBox.Show(Resources.MsgExportSucceed, Resources.msgTitleTip, MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                    }
                    catch (System.Exception ex)
                    {

                        MessageBox.Show(Resources.MsgExportFailed, Resources.msgTitleTip, MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                        if (excel == null)
                        {
                            excel.Quit();
                        }
                    }

                }, false, true);
                wating.ShowDialog();
                Clipboard.Clear(); // 清空剪贴板（放在Waitingform中,导致错误 "在可以调用 OLE 之前，必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记"）
                foreach (DataGridViewRow row in dgv.Rows) // 取消选择
                {
                    row.Selected = false;
                }
            }
        }
        public static void DataGridViewToExcel(DataGridView dgv, string strTitle)//, int SheetIndex
        {
            //总可见列数，总可见行数
            //int colCount = dgv[].Columns.GetColumnCount(DataGridViewElementStates.Visible);
            //int rowCount = dgv.Rows.GetRowCount(DataGridViewElementStates.Visible);
            //dataGridView 没有数据提示
            if (dgv == null|| dgv.Rows.Count == 0)
            {
                MessageBox.Show(Resources.msgNoDataInTable, Resources.msgTitleTip, MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
            }
            else
            {
                //选择创建文件的路径
                SaveFileDialog save = new SaveFileDialog();
                save.DefaultExt = "xls";
                save.AddExtension = true;
                save.Filter = Resources.txtSaveFileFilterXlsx;
                save.Title = Resources.txtPleaseSelSavePath;
                //save.InitialDirectory = strDefPath;
                //save.FileName = strDefPath;
                if (save.ShowDialog() != DialogResult.OK)
                {
                    return;
                }

                string fileName = save.FileName;
                //MessageBox.Show(save.FileName);
                // 创建Excel对象
                Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
                if (excel == null)
                {
                    MessageBox.Show(Resources.MsgCannotOpenExcel, Resources.msgTitleTip, MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                    return;
                }
                //创建Excel工作薄
                Workbook excelBook = excel.Workbooks.Add(true);
                Worksheet excelSheet = null;
                // 创建工作表
                excelBook.Worksheets.Add(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
                
                //生成字段名称

                    excelSheet = (Worksheet)excelBook.Worksheets[1];
                    excelSheet.Activate();
                    int k = 0;
                    excel.Cells[1, 1] = strTitle;
                    excel.Cells[2, 1] = DateTime.Now.ToLongDateString();
                    for (int i = 0; i < dgv.ColumnCount; i++)
                    {
                        if (dgv.Columns[i].Visible)  //不导出隐藏的列
                        {
                            excel.Cells[3, k + 1] = dgv.Columns[i].HeaderText;
                            k++;
                        }
                    }
                    //填充数据
                    for (int i = 0; i < dgv.RowCount; i++)
                    {
                        k = 0;
                        for (int j = 0; j < dgv.ColumnCount; j++)
                        {
                            if (dgv.Columns[j].Visible)  //不导出隐藏的列
                            {
                                if (dgv[j, i].Value != null)
                                {
                                   excel.Cells[i + 4, k + 1] = dgv[j, i].Value.ToString();
                                }
                                else
                                {
                                    excel.Cells[i + 4, k + 1] = "";
                                }
                            }
                            k++;
                        }
                    }
                

                try
                {
                    excel.DisplayAlerts = false;
                    excelBook.Saved = true;

                    int FormatNum;//保存excel文件的格式
                    string Version;//excel版本号
                    Version = excel.Version;//获取你使用的excel 的版本号
                    if (Convert.ToDouble(Version) < 12)//You use Excel 97-2003
                    {
                        FormatNum = -4143;
                    }
                    else//you use excel 2007 or later
                    {
                        FormatNum = 56;
                    }
                    /*
                     导致“文件格式与扩展名指定格式不一致”这个问题，是因为大多数人在导出excel文件的时候，都是默认保存excel的格式,
                    也就是直接workbook.Save(path)或者workbook.SaveAs(path).进而忽略了SaveAs方法里面的参数。与保存excel文件格式有
                    关的是它第二个参数FileForMat.
                    FileFormat
                    类型：System.Object XlFileFormat的值之一，指定保存文件时要使用的文件格式。对于原有文件，默认格式为最后一种
                    指定文件格式。对于新文件，默认格式为所用excel版本的格式。PS：当导出的excel文件的扩展名与所用excel版本的扩展名
                    不一致的时候就会出现“文件格式与扩展名指定格式不一致的”错误，当低版本打开excel文件时不但会提示这样的错误，还
                    会是乱码。
                     */
                    excelBook.SaveAs(fileName, FormatNum, Missing.Value, Missing.Value, Missing.Value,
                                    Missing.Value, XlSaveAsAccessMode.xlShared, Missing.Value, Missing.Value, Missing.Value,
                                    Missing.Value, Missing.Value);
                    excel.Quit();  // 保存后应该关闭EXCEL
                    MessageBox.Show(Resources.MsgExportSucceed ,Resources.msgTitleTip, MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                }
                catch
                {
                    MessageBox.Show(Resources.MsgExportFailed, Resources.msgTitleTip, MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                }
            }
        }
        public static void RefreshChlId()
        {
            for (int i = 0;i < ChlList.Count;i++)
            {
                ChlList[i].baseChlPara.ChannelId = i;
                Channel chl = ChlList[i];
                ReFreshDevId(ref chl);
            }
        }
        public static void ReFreshDevId(ref Channel Chl)
        {
            if (Chl is InnerModbusChannel)
            {
                InnerModbusChannel channel = Chl as InnerModbusChannel;
                for (int i = 0; i < channel.m_DeviceList.Count;i++ )
                {
                    channel.m_DeviceList[i].ChannelId = Chl.baseChlPara.ChannelId;
                    channel.m_DeviceList[i].DeviceId = i;
                }
            }
        }
        
        public static List<Channel> ChannelBubbleSort(List<Channel> listItem)
        {
            Channel temp;
            //第一层循环： 表明要比较的次数，比如list.count个数，肯定要比较count-1次
            for (int i = 0; i < listItem.Count - 1; i++)
            {
                //list.count-1：取数据最后一个数下标，
                //j>i: 从后往前的的下标一定大于从前往后的下标，否则就超越了。
                for (int j = listItem.Count - 1; j > i; j--)
                {
                    //如果前面一个数大于后面一个数则交换
                    if (listItem[j - 1].baseChlPara.ChannelId > listItem[j].baseChlPara.ChannelId)
                    {
                        temp = listItem[j - 1];
                        listItem[j - 1] = listItem[j];
                        listItem[j] = temp;
                    }
                }
            }
            return listItem;
        }
    }

    sealed class LangChange
    {
        private static string _strLanguage = "zh-CN";
        /// <summary>
        /// 语言选择 0:中文 1：English
        /// </summary>
        public static void SelectLang(int selectedIndex)
        {
            switch (selectedIndex)
            {
                case 0:
                    _strLanguage = "zh-CN";
                    break;
                case 1:
                    _strLanguage = "en";
                    break;
                default:
                    _strLanguage = "zh-CN";
                    break;
            }
            System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(_strLanguage);
            INIFile file = new INIFile(AppMain.StartPath + Properties.Resources.RegisterPath + "Languege.ini");
            file.ClearAllSection();
            file.IniWriteValue("当前语言", "语言信息", _strLanguage);
        }

        /// <summary>
        /// 启动时调用
        /// </summary>
        /// <param name="strLang"></param>
        public static void SelectLang(string strLang)
        {
            _strLanguage = strLang;
        }
        /// <summary>
        ///  获取语言ID 0:中文 1:Englsh
        /// </summary>
        /// <returns></returns>
        public static int GetLangId()
        {
            switch (_strLanguage)
            {
                case "zh-CN":
                    return 0;
                case "en":
                    return 1;
                default:
                    return 0;
            }
        }
        /// <summary>
        /// 设置当前程序的界面语言
        /// </summary>
        /// <param name="lang">language:zh-CN, en-US</param>
        /// <param name="form">窗体实例</param>
        /// <param name="formType">窗体类型</param>
        public static void SetFormLang(Form form, Type formType)
        {
           
            if (form != null)
            {
                System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(formType);
                resources.ApplyResources(form, "$this");
                AppLang(form, resources);
            }
        }

        /// <summary>
        /// 遍历窗体所有控件，针对其设置当前界面语言
        /// </summary>
        /// <param name="control"></param>
        /// <param name="resources"></param>
        private static void AppLang(Control control, System.ComponentModel.ComponentResourceManager resources)
        {
            if (control is MenuStrip)
            {
                resources.ApplyResources(control, control.Name);
                MenuStrip ms = (MenuStrip)control;
                if (ms.Items.Count > 0)
                {
                    foreach (ToolStripMenuItem c in ms.Items)
                    {
                        AppLang(c, resources);
                    }
                }
            }
            else if (control is TreeView)
            {
                TreeView tr = (TreeView)control;
                if (tr.Nodes.Count > 0)
                {
                    foreach (TreeNode c in tr.Nodes)
                    {
                        if (tr.Name == "tvDevices") 
                        {
                            c.Text = Resources.txtMeterList;
                        }
                        AppLang(c, resources);
                    }
                }
            }

            if (control.ContextMenuStrip != null)
            {
                resources.ApplyResources(control.ContextMenuStrip, control.ContextMenuStrip.Name);
                ContextMenuStrip ms = control.ContextMenuStrip;
                if (ms.Items.Count > 0)
                {
                    foreach (ToolStripMenuItem tsmi in ms.Items)
                    {
                        AppLang(tsmi, resources);
                    }
                }
            }
            foreach (Control c in control.Controls)
            {
                resources.ApplyResources(c, c.Name);
                AppLang(c, resources);
                if (c is DataGridView)
                {
                    DataGridView dgv = (DataGridView)c;
                    foreach (DataGridViewColumn col in dgv.Columns)
                    {
                        resources.ApplyResources(col, col.Name);
                    }
                }
            }
        }
        /// <summary>
        /// 遍历树节点
        /// </summary>
        /// <param name="item"></param>
        /// <param name="resources"></param>
        private static void AppLang(TreeNode item, System.ComponentModel.ComponentResourceManager resources)
        {
            if (item != null)
            {
                resources.ApplyResources(item, item.Name);

                if (item.Nodes.Count > 0)
                {
                    foreach (TreeNode c in item.Nodes)
                    {
                        AppLang(c, resources);
                    }
                }
            }
        }
        /// <summary>
        /// 遍历菜单
        /// </summary>
        /// <param name="item"></param>
        /// <param name="resources"></param>
        private static void AppLang(ToolStripMenuItem item, System.ComponentModel.ComponentResourceManager resources)
        {
            if (item != null)
            {
                resources.ApplyResources(item, item.Name);
                ToolStripMenuItem tsmi = (ToolStripMenuItem)item;
                if (tsmi.DropDownItems.Count > 0)
                {
                    foreach (ToolStripMenuItem c in tsmi.DropDownItems)
                    {
                        AppLang(c, resources);
                    }
                }
            }
        }
    }
}
